# -*- coding: utf-8 -*-

import logging
import traceback

from odoo import models, fields, api
from odoo.http import request
from odoo_contrib import models as contrib_models

from ..utils.common import now_ts
from ..utils.exceptions import WechatAuthException


logger = logging.getLogger(__name__)


class User(contrib_models.SchemaModel):
    _name = 'wechat.user'

    openid = fields.Char(required=True, index=True)
    unionid = fields.Char(index=True)
    wxid = fields.Char()
    nickname = fields.Char(string='昵称')
    avatar = fields.Char(string='头像')
    gender = fields.Integer(string='性别')
    city = fields.Char(string='城市')
    province = fields.Char(string='省份')
    country = fields.Char(string='国家')
    language = fields.Char(string='语言')

    session_key = fields.Char()

    mobile = fields.Char(string='手机')
    subscribed = fields.Boolean(string='已订阅公众号', default=False)

    user_source = fields.Char(string='用户来源')

    latest_visit_ts = fields.Integer(default=now_ts)

    app_id = fields.Many2one('wechat.miniapp')
    site = fields.Char()

    _sql_constraints = [
        ('uq_wechat_user_openid', 'UNIQUE(openid)', 'Duplicated wechat user openid')
    ]

    @api.multi
    def name_get(self):
        names = []
        for user in self:
            # names.append((user.id, '{}-{}'.format(user.id, user.nickname or '')))
            names.append((user.id, user.nickname or str(user.id)))
        return names

    @api.model
    def login(self, session_info):
        openid = session_info.get('openid')
        unionid = session_info.get('unionid')
        session_key = session_info.get('session_key')

        nickname = session_info.get('nickname')
        gender = session_info.get('gender')
        city = session_info.get('city')
        province = session_info.get('province')
        country = session_info.get('country')
        language = session_info.get('language')

        if openid is None:
            logger.error(
                'No openid found when login, session_info: %s',
                session_info,
            )
            raise WechatAuthException(
                errcode=101002,
            )
        privileged = self.sudo(self.env.ref('wechat.host_user'))
        user = privileged.search([
            ('openid', '=', openid)
        ])
        if not user:
            if session_info['site'] is None:
                domains = [('default', '=', True)]
            else:
                domains = [('name', '=', session_info['site'])]
            miniapp = self.env['wechat.miniapp'].sudo().search(domains)
            if miniapp:
                session_info['app_id'] = miniapp[0].id
            user = self.sudo().create(session_info)
        else:
            user = user[0]

        update_info = {}
        if unionid and user.unionid != unionid:
            update_info['unionid'] = unionid
        if session_key and user.session_key != session_key:
            update_info['session_key'] = session_key

        if nickname and user.nickname != nickname:
            update_info['nickname'] = nickname
        if gender and user.gender != gender:
            update_info['gender'] = gender
        if city and user.city != city:
            update_info['city'] = city
        if province and user.province != province:
            update_info['province'] = province
        if country and user.country != country:
            update_info['country'] = country
        if language and user.language != language:
            update_info['language'] = language

        if update_info:
            user.write(update_info)

        return user

    @api.model
    def subscribe(self, openid):
        privileged = self.sudo(self.env.ref('wechat.host_user'))
        user = privileged.search([
            ('openid', '=', openid)
        ])
        if not user:
            user = self.sudo().create({
                'openid': openid,
                'subscribed': True,
            })
        else:
            user.write({
                'subscribed': True,
            })

    @api.model
    def unsubscribe(self, openid):
        privileged = self.sudo(self.env.ref('wechat.host_user'))
        user = privileged.search([
            ('openid', '=', openid)
        ])
        if not user:
            user = self.sudo().create({
                'openid': openid,
                'subscribed': False,
            })
        else:
            user.write({
                'subscribed': False,
            })

    @property
    def redis_payload(self):
        user = self[0]
        return {
            'id': user.id,
            'openid': user.openid or None,
            'unionid': user.unionid or None,
            'nickname': user.nickname or None,
            'avatar': user.avatar or None,
            'gender': user.gender or None,
            'city': user.city or None,
            'province': user.province or None,
            'country': user.country or None,
            'language': user.language or None,
            'session_key': user.session_key or None,
            'mobile': user.mobile or None,
            'site': user.site or None,
            'user_type': user.user_type,
        }

    @property
    def user_type(self):
        return 'wechat'

    @classmethod
    def get_proxy(cls, **kwargs):
        if 'id' not in kwargs:
            logger.error(
                'no id found in kwargs while getting user proxy %s',
                kwargs,
            )
            return None
        return WechatUserProxy(**kwargs)

    def update_profile(self, **info):
        if info:
            self.ensure_one()
            self.write(info)


class BaseUserProxy(object):
    _proxied_class = None

    def __init__(self, user=None, **kwargs):
        self._user = user
        self._proxied_keys = []
        for k, v in kwargs.items():
            self.__dict__[k] = v
            self._proxied_keys.append(k)

    def __getattr__(self, name):
        try:
            val = getattr(self.proxied, name)
        except:
            val = None
        return val

    @property
    def proxied(self):
        if self._user is None:
            self._user = request.env[self._proxied_class].search([('id', '=', self.id)])
            if not self._user:
                logger.error(
                    'PROXIED WECHAT-USER/ADMIN NOT FOUND!! id: %s',
                    self.id,
                )
                self._user = None
            else:
                for k in self._proxied_keys:
                    self.__dict__.pop(k, None)
                self._user = self._user[0]
        return self._user


class WechatUserProxy(BaseUserProxy):
    _proxied_class = 'wechat.user'
